package com.wom.worldmaker;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;

import javax.imageio.ImageIO;

import com.wom.blockfeatures.BlockUtils;
import com.wom.blocks.AbstractBlock;
import com.wom.blocks.AirBlock;
import com.wom.blocks.DirtBlock;
import com.wom.blocks.LavaBlock;
import com.wom.blocks.RockBlock;
import com.wom.blocks.SandBlock;
import com.wom.blocks.Tree;
import com.wom.blocks.TreeBlock;
import com.wom.blocks.TreeLeavesBlock;
import com.wom.blocks.VoidRock;
import com.wom.blocks.WaterBlock;
import com.wom.gui.BlockTypes;
import com.wom.gui.GameApplet;
import com.wom.gui.SelectionRectangle;
import com.wom.player.ThePlayer;

public class GameWorld {



	public static  AbstractBlock[][] gameBlocks;
	public static ThePlayer player;
	public static  BufferedImage tileTextures;
	public  boolean mouseMoving=false;
	public static  Point mouse=new Point(0,0);
	private int renderWidth;
	private int renderHeight;
	private int blockSize;
	public SelectionRectangle selectRect=new SelectionRectangle();
	ArrayList<Tree> trees=new ArrayList<>();
	GameApplet app;


	public GameWorld(GameApplet gameApplet){
		app=gameApplet;
		gameBlocks=new AbstractBlock[GameProperties.worldWidth][GameProperties.worldHeight];
		player=new ThePlayer(0,0, Color.PINK, "player");
		selectRect.setBounds(0,0,blockSize,blockSize);
		makeWorld();
		//player.moveToGrid(10, 5);

		try {
			tileTextures=ImageIO.read(new File("res/tilemap.png"));
			System.out.println("loaded tileset");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}


	public void makeWorld(){

		fillWorldWithBlock(BlockTypes.air);

		makeBottomLavaLayer();

		makeRockLayer();

		makeDirtLayer();

		makeSandLayer();
		updateWorld();

		makeRandomLayer();

		// make random dirt



		//makeSeaLayer();

		makeTrees(50);


		makeBottomVoid();

		for(int x=0;x<gameBlocks.length;x++){
			for(int y=30;y<gameBlocks[0].length;y++){
				if(gameBlocks[x][y] instanceof DirtBlock){
					gameBlocks[x][y].updateBlock();
				}
			}

		}
	}


	private void makeTrees(int c) {

		Random r=new Random();

		for(int x=0;x<c;x++){

			trees.add(new Tree(r.nextInt(gameBlocks.length), 29));
		}


	}


	private void makeSeaLayer() {

		Random r=new Random();



		for(int x=r.nextInt(gameBlocks.length/5);x<gameBlocks.length;x++){
			for(int y=30;y<60;y++){
				gameBlocks[x][y]=new WaterBlock(x, y);
			}
		}

	}


	private void makeSandLayer() {
		Random r=new Random();
		for(int x=0;x<gameBlocks.length;x++){
			for(int y=30;y<gameBlocks[0].length-59;y++){
				if(r.nextInt(10)<3){
					gameBlocks[x][y]=new SandBlock(x, y);
				}
			}
		}

	}


	private void makeRandomLayer() {
		// TODO Auto-generated method stub

	}


	private void makeDirtLayer() {
		Random r=new Random();
		for(int x=0;x<gameBlocks.length;x++){
			for(int y2=30;y2<gameBlocks[0].length-59;y2++){
				if(r.nextInt(20)<19){
					gameBlocks[x][y2]=new DirtBlock(x, y2);
				}

			}	
		}

	}


	private void makeRockLayer() {

		Random r=new Random();
		for(int x=0;x<gameBlocks.length;x++){
			for(int y2=gameBlocks[0].length-60;y2<gameBlocks[0].length-10;y2++){
				if(r.nextInt(20)<17){
					gameBlocks[x][y2]=new RockBlock(x, y2);
				}
			}
		}

	}


	private void makeBottomLavaLayer() {
		for(int x=0;x<gameBlocks.length;x++){
			for(int y=gameBlocks[0].length-10;y<gameBlocks[0].length-2;y++){
				gameBlocks[x][y]=new LavaBlock(x, y);
			}
		}

	}


	private void fillWorldWithBlock(BlockTypes fillBlock) {
		// make the world of air first
		for(int x=0;x<gameBlocks.length;x++){
			for(int y=0;y<gameBlocks[0].length;y++){


				if(fillBlock==BlockTypes.air){
					gameBlocks[x][y]=new AirBlock(x, y);
				}

			}	
		}
	}


	private void makeBottomVoid() {
		// mmake bottom void barrier

		int y=gameBlocks[0].length-1;
		for(int x=0;x<gameBlocks.length;x++){

			gameBlocks[x][y]=new VoidRock(x, y-1);

		}
	}

	public void renderWorld(Graphics  g){
		renderBlocks(g);
		//renderObjects(g);
		renderPlayer(g);
		renderSelection(g);
	}




	private void renderSelection(Graphics g) {

		//		AbstractBlock b=BlockUtils.getOnBlock(mouse.x, mouse.y);
		//		if(b!=null){
		//
		//			Point i=getBlockSelectionDistanceFromPlayer(b);
		g.setColor(Color.RED);

		//if(Math.abs(i.x) <5 && Math.abs(i.y) <5 )
		//g.drawRect((int) (b.getxPos()*(int)GameProperties.blockSize-player.cam.x), b.getyPos()*GameProperties.blockSize-(int)player.cam.y, GameProperties.blockSize, GameProperties.blockSize);

		if(selectRect.enabled){
			g.drawRect(selectRect.x,selectRect.y, selectRect.width,selectRect.height);
		}



	}

	private Point getBlockSelectionDistanceFromPlayer(AbstractBlock b){

		Point i=new Point(0,0);
		if(b==null){return i;}
		i.x=(int) ((player.x-b.x)/blockSize);
		i.y=(int) ((player.y-b.y)/blockSize);


		//System.out.println(i.x+","+i.y);

		return i;

	}




	private void renderPlayer(Graphics g) {
		player.renderPlayer(g);

	}


	private void renderBlocks(Graphics g) {
		//		for(int x=0;x<gameBlocks.length;x++){
		//			for(int y=0;y<gameBlocks[0].length;y++){
		//				gameBlocks[x][y].renderBlock(g);
		//			}	
		//		}
		renderWidth=(int) ((player.cam.x/GameProperties.blockSize)+(GameProperties.pixelSize.width/GameProperties.blockSize));
		renderHeight=(int) ((player.cam.y/GameProperties.blockSize)+(GameProperties.pixelSize.height/GameProperties.blockSize));
		blockSize=GameProperties.blockSize;

		for(int x=(int) (player.cam.x/blockSize);x<renderWidth+1;x++){
			for(int y=(int) (player.cam.y/blockSize);y<renderHeight+1;y++){

				if(x>=0 && x<gameBlocks.length && y>=0 && y<gameBlocks[0].length){


					if(blockIsVisibleToPlayer(gameBlocks[x][y])){
						gameBlocks[x][y].renderBlock(g);

					}
				}

			}	
		}
	}

	public boolean blockIsVisibleToPlayer(AbstractBlock visibilityBlock) {

		boolean x = false,y = false, b=false;
		//		if(!(Math.abs(visibilityBlock.getxPos()-(player.x/blockSize))>5)){
		//			x=true;
		//		}
		//		if(!(Math.abs(visibilityBlock.getyPos()-(player.y/blockSize))>5)){
		//			y=true;
		//		}
		if(visibilityBlock instanceof AirBlock ){
			return true;
		}

		if((Math.abs(visibilityBlock.getxPos()-(player.x/blockSize))<5)){
			x=true;



		}

		if((Math.abs(visibilityBlock.getyPos()-(player.y/blockSize))<5)){
			y=true;



		}

		if(BlockUtils.getBlockBelow(visibilityBlock) !=null){
			b=true;	
		}
		if(x && y && b){
				return true;
			}else{
				return false;
			}
	


	}


	public void updatePlayer(){

		player.updatePlayer();

		updateMouse();
	}

	private void updateMouse() {

		AbstractBlock b=BlockUtils.getOnBlock(mouse.x, mouse.y);
		if(b==null){return;}

		// if the selector is outside of 5 blocks dont update
		Point p=getBlockSelectionDistanceFromPlayer(b);
		if(b!=null && Math.abs(p.x) <5 && Math.abs(p.y)<5){

			selectRect.enabled=true;
			selectRect.setBounds(b.getxPos()*blockSize-(int)player.cam.x,b.getyPos()*blockSize-(int)player.cam.y,blockSize,blockSize);
		}else{
			selectRect.enabled=false;
		}

		// if the recticle is in mid air dont show
		if(!BlockUtils.isIsolatedBlock(b, BlockTypes.air) && b !=null){
			selectRect.enabled=true;
			selectRect.setBounds(b.getxPos()*blockSize-(int)player.cam.x,b.getyPos()*blockSize-(int)player.cam.y,blockSize,blockSize);
		}else{
			selectRect.enabled=false;

		}


		if(b==null){
			app.mouseOnBlock="No Block";
		}else{
			app.mouseOnBlock=b.toString();
		}

		if(selectRect.enabled){
			if(player.mousePressedLeft){
				addBlock(mouse);
			}

			if(player.mousePressedRight){

				removeBlock(mouse);
			}

		}


	}


	private void addBlock(Point p) {
		AbstractBlock block=BlockUtils.getOnBlock(p.x,p.y);

		// check if block is placed in players position space
		if(block==null){return;}

		if(block.intersects(player.getBounds())){
			System.out.println("cant place blocks over player position..");

			return;

		}


		if(block instanceof AirBlock){
			// place only 1 at a time
			player.mousePressedLeft=false;
			switch (app.addBlockType){

			case Dirt:
				block=new DirtBlock(block.getxPos(), block.getyPos());
				gameBlocks[block.getxPos()][block.getyPos()]=block;
				break;

			case Sand:

				if(block.intersects(player.r)){
					System.out.println("Sand block hits player");
					return;
				}

				block=new SandBlock(block.getxPos(), block.getyPos());
				gameBlocks[block.getxPos()][block.getyPos()]=block;
				break;

			case Rock:
				block=new RockBlock(block.getxPos(), block.getyPos());
				gameBlocks[block.getxPos()][block.getyPos()]=block;
				break;

			case water:
				block=new WaterBlock(block.getxPos(), block.getyPos());
				gameBlocks[block.getxPos()][block.getyPos()]=block;
				break;


			default:
				break;

			}



		}

	}


	private void removeBlock(Point p){
		//System.out.println("mouse2:"+p.x+","+p.y);
		// remove only 1 at a time
		//player.mousePressedRight=false;
		AbstractBlock block=BlockUtils.getOnBlock(p.x,p.y);

		if(block==null)return;

		if(!(block instanceof VoidRock)){


			// check if sand is being removed, if so remove only one at a time
			if(block instanceof SandBlock){

				if(!((SandBlock) block).breakable.isDead){
					((SandBlock) block).breakable.causeDamage(20);
				}else{
					BlockUtils.changeInto(block.getxPos(),block.getyPos(), BlockTypes.air);
					player.mousePressedRight=false;
				}
			}

			if(block instanceof DirtBlock){

				if(!((DirtBlock) block).breakable.isDead){
					((DirtBlock) block).breakable.causeDamage(20);
				}else{
					BlockUtils.changeInto(block.getxPos(),block.getyPos(), BlockTypes.air);
					player.mousePressedRight=false;
				}

			}

			if(block instanceof RockBlock){

				if(!((RockBlock) block).breakable.isDead){
					((RockBlock) block).breakable.causeDamage(20);
					System.out.println(((RockBlock) block).breakable.getHealth());
				}else{
					BlockUtils.changeInto(block.getxPos(),block.getyPos(), BlockTypes.air);
					player.mousePressedRight=false;
				}
			}

			if(block instanceof TreeBlock){

				if(!((TreeBlock) block).breakable.isDead){
					((TreeBlock) block).breakable.causeDamage(20);
					System.out.println(((TreeBlock) block).breakable.getHealth());
				}else{
					BlockUtils.changeInto(block.getxPos(),block.getyPos(), BlockTypes.air);
					player.mousePressedRight=false;
				}
			}
			if(block instanceof TreeLeavesBlock){

				if(!((TreeLeavesBlock) block).breakable.isDead){
					((TreeLeavesBlock) block).breakable.causeDamage(20);
					System.out.println(((TreeLeavesBlock) block).breakable.getHealth());
				}else{
					BlockUtils.changeInto(block.getxPos(),block.getyPos(), BlockTypes.air);
					player.mousePressedRight=false;
				}
			}
		}

	}

	public void updateTrees(){
		for(Tree t:trees){
			t.updateTree();
		}

	}

	public void updateWorld(){


		renderWidth=(int) ((player.cam.x/GameProperties.blockSize)+(GameProperties.pixelSize.width/GameProperties.blockSize));
		renderHeight=(int) ((player.cam.y/GameProperties.blockSize)+(GameProperties.pixelSize.height/GameProperties.blockSize));
		blockSize=GameProperties.blockSize;

		for(int x=(int) (player.cam.x/blockSize);x<renderWidth+1;x++){
			for(int y=(int) (player.cam.y/blockSize);y<renderHeight+1;y++){

				if(x>=0 && x<gameBlocks.length && y>=0 && y<gameBlocks[0].length){
					gameBlocks[x][y].updateBlock();
				}

			}	
		}

		updateTrees();
	}


}
